#include "simulation.h"

SJFSimulation::SJFSimulation(int argc, char **argv) : Simulation(argc, argv) {

}

//schedule a departure event for a given customer
void SJFSimulation::schedule_departure(Customer *customer) {
	//set the service time
	//Ts = expntl(1/mu, kSeed_service);
	//customer->service_time_ = Ts;
	//create a departure event and add it to the event list
	EventNode *current_departure = new EventNode('D', customer, 
//											 sim_time + Ts);
												 sim_time + customer->service_time_);
	event_list_add(current_departure);
}

//process an arrival event
void SJFSimulation::process_arrival(EventNode *next_event) {
	//generate the next inter-arrival time
	Ta = expntl(1/lambda, kSeed_arrival);
	Ts = expntl(1/mu, kSeed_service);
	//set the simulation time to the time of the next event
	sim_time = next_event->time_;
	//create a new customer for the next arrival and add it to the event list
	//if the queue is not full, add the customer to the queue, increment n.
	//if there is only one customer in the queue, schedule a departure event for this customer
	//schedule the next arrival event
	//
	//else the customer is lost and cannot be serviced
	//create a new lost event and add it to the event list
	//cout << "n = " << n << ", kcpu = " << kcpu << endl;
	if (n < kcpu) {
		arrival_count++;
		if(customer_queue.empty()) {
			customer_queue.push(next_event->customer_);
		} else {
			Customer *current = customer_queue.top();
			//cout << "top id = " << customer_queue.top()->id_ << endl;
			//cout << "before first print" << endl;
			//print_queue();
			customer_queue.pop();
			customer_queue.push(next_event->customer_);
			double temp = current->service_time_;
			current->service_time_ = 0;
			customer_queue.push(current);
			current->service_time_ = temp;
			//print_queue();
			//cout << "after first print" << endl;
			//cout << "top id = " << customer_queue.top()->id_ << endl;
		}
//		print_queue();
		//customer_queue.push_front(next_event->customer_);
		/*if (m == 0) {
			customer_queue.push_back(next_event->customer_);
		} else {
			customer_queue.push_front(next_event->customer_);
		}*/
		n++;
		//cout << "here, n = " << n << endl;
		if (n == 1) {
			//schedule_departure(next_event->customer_);
			schedule_departure(customer_queue.top());
		}
		Customer *customer = new Customer(total_arrival_count++, sim_time + Ta, Ts, 0, 0, false, false); 
		customer_list.push_back(customer);
		EventNode *next_arrival = new EventNode('A', customer, sim_time + Ta);
		event_list_add(next_arrival);

	} else {
		next_event->customer_->lost_ = true;
		next_event->customer_->serviced_ = false;
		//customer->lost_ = true;
		//customer->serviced_ = false;
		EventNode *lost_arrival = new EventNode('L', next_event->customer_, sim_time);
		event_list_add(lost_arrival);
	}
}

//process the lost event
void SJFSimulation::process_lost(EventNode *next_event) {
	//generate the next inter-arrival time
	Ta = expntl(1/lambda, kSeed_arrival);
	Ts = expntl(1/mu, kSeed_service);
	//set the simulation time to the time of the next event
	sim_time = next_event->time_;
	//create a new customer for the next arrival and add it to the event list
	Customer *customer = new Customer(total_arrival_count++, sim_time + Ta, Ts, 0, 0, false, false); 
	customer_list.push_back(customer);
	//if the queue is not full, schedule the next event with the newly created customer
	//note that we since the customore for next_event is lost, we do not add it to the queue
	//
	//else
	//this customer is also lost and cannot be serviced
	//create a new lost event and add it to the event list
	if (n < kcpu) {
		EventNode *next_arrival = new EventNode('A', customer, sim_time + Ta);
		event_list_add(next_arrival);

	} else {
		customer->lost_ = true;
		customer->serviced_ = false;
		EventNode *lost_arrival = new EventNode('L', customer, sim_time + Ta);
		event_list_add(lost_arrival);
	}
}

void SJFSimulation::process_departure(EventNode *next_event) {
	//if the queue is not empty, select the front customer in the queue as the departing_customer
	//set the simulation time to the time of the next_event
	//set the departure_time_, serviced_ and lost_ properties of this customer
	//remove the customer from the queue
	//set the number of customers in the queue parameter for this customer
	//decrement n
	//increment the serve_count
	//if there are still customers in the queue, schedule the next departure event
	if (! customer_queue.empty()) {
		if (next_event->customer_->id_ != customer_queue.top()->id_) {
			cout << "caught" << next_event->customer_->id_ << " " 
				 << customer_queue.top()->id_ << endl;
		}
		//cout << "queue top = " << customer_queue.top()->id_ << endl;
		//cout << "next event customer = " << next_event->customer_->id_ << endl;
		Customer *departing_customer = next_event->customer_;
		sim_time = next_event->time_;
		departing_customer->departure_time_ = sim_time;
		departing_customer->serviced_ = true;
		departing_customer->lost_ = false;
		departing_customer->departure_number_ = ++departure_count;
		customer_queue.pop();
		departing_customer->customers_after_ = customer_queue.size();
		n--;
		serve_count++;
		if (n > 0) {
			schedule_departure(customer_queue.top());
		}
	} 
}

void SJFSimulation::print_queue() {
	vector<Customer *> customers_in_queue;
	while (! customer_queue.empty()) {
		customers_in_queue.push_back(customer_queue.top());
		customer_queue.pop();
	}

	for (uint32_t index = 0; index < customers_in_queue.size(); ++index) {
		cout << customers_in_queue[index]->id_ << " ";
		customer_queue.push(customers_in_queue[index]);
	}
	cout << endl;
}
